package com.gec.anan.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gec.anan.common.constant.RedisConstant;
import com.gec.anan.common.execption.AnanException;
import com.gec.anan.common.result.ResultCodeEnum;
import com.gec.anan.model.entity.order.*;
import com.gec.anan.model.enums.OrderStatus;
import com.gec.anan.model.form.order.OrderInfoForm;
import com.gec.anan.model.form.order.StartDriveForm;
import com.gec.anan.model.form.order.UpdateOrderBillForm;
import com.gec.anan.model.form.order.UpdateOrderCartForm;
import com.gec.anan.model.vo.base.PageVo;
import com.gec.anan.model.vo.order.*;
import com.gec.anan.order.mapper.*;
import com.gec.anan.order.service.OrderInfoService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {


    @Autowired
    OrderInfoMapper orderInfoMapper;
    @Autowired
    OrderMonitorMapper orderMonitorMapper;
    @Autowired
    OrderStatusLogMapper orderStatusLogMapper;
    @Autowired
    OrderBillMapper orderBillMapper;
    @Autowired
    OrderProfitsharingMapper orderProfitsharingMapper;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    //結束订单：更新订单信息【状态、费用、距离。。。】、order_bill订单账单信息、order_profitsharing分账
    @Override
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        //1、更新订单信息
        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getId, updateOrderBillForm.getOrderId())
                .eq(OrderInfo::getDriverId, updateOrderBillForm.getDriverId());
        //entity
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.END_SERVICE.getStatus());
        updateOrderInfo.setRealAmount(updateOrderBillForm.getTotalAmount());
        updateOrderInfo.setFavourFee(updateOrderBillForm.getFavourFee());
        updateOrderInfo.setEndServiceTime(new Date());
        updateOrderInfo.setRealDistance(updateOrderBillForm.getRealDistance());
        //
        int update = orderInfoMapper.update(updateOrderInfo, wrapper);
        if (update > 0) {
            //2、订单账单信息
            //记录日志
            this.log(updateOrderBillForm.getOrderId(), OrderStatus.END_SERVICE.getStatus());
            //插入实际账单数据
            OrderBill orderBill = new OrderBill();
            BeanUtils.copyProperties(updateOrderBillForm, orderBill);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(orderBill.getTotalAmount());
            orderBillMapper.insert(orderBill);
            //3、order_profitsharing分账
            OrderProfitsharing orderProfitsharing = new OrderProfitsharing();
            BeanUtils.copyProperties(updateOrderBillForm, orderProfitsharing);
            orderProfitsharing.setDriverIncome(updateOrderBillForm.getDriverIncome());
            orderProfitsharing.setPlatformIncome(updateOrderBillForm.getPlatformIncome());
            orderProfitsharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitsharing.setRuleId(updateOrderBillForm.getProfitsharingRuleId());
            orderProfitsharing.setStatus(1);
            System.out.println("--------orderProfitsharingMapper - updateOrderBillForm--->" + JSONObject.toJSONString(updateOrderBillForm));
            System.out.println("-----------orderProfitsharingMapper--->" + JSONObject.toJSONString(orderProfitsharing));
            orderProfitsharingMapper.insert(orderProfitsharing);
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }


    //乘客端分页查找订单
    @Override
    public PageVo findCustomerOrderPage(Page<OrderInfo> pageVoPage, Long customerId) {
        IPage<OrderListVo> pageInfo = orderInfoMapper.selectCustomerOrderPage(pageVoPage, customerId);

        return new PageVo<>(pageInfo.getRecords(), pageInfo.getPages(), pageInfo.getTotal());
    }

    //司机端分页查找订单
    @Override
    public PageVo findDriverOrderPage(Page<OrderInfo> pageParam, Long driverId) {
        IPage<OrderListVo> pageInfo = orderInfoMapper.selectDriverOrderPage(pageParam, driverId);
        return new PageVo(pageInfo.getRecords(), pageInfo.getPages(), pageInfo.getTotal());
    }

    //更新优惠券信息
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateCouponAmount(Long orderId, BigDecimal couponAmount) {
        int i = orderBillMapper.updateCouponAmount(orderId, couponAmount);
        if(i!=1){
            throw new AnanException(ResultCodeEnum.DATA_ERROR);
        }
        return true;
    }

    //获取账单信息
    @Override
    public OrderBillVo getOrderBillInfo(Long orderId) {
        LambdaQueryWrapper<OrderBill> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderBill::getOrderId, orderId);
        OrderBill orderBill = orderBillMapper.selectOne(queryWrapper);

        OrderBillVo orderBillVo = new OrderBillVo();
        BeanUtils.copyProperties(orderBill, orderBillVo);
        return orderBillVo;
    }

    //根据id获取分账信息(平台)
    @Override
    public OrderProfitsharingVo getOrderProfitsharing(Long orderId) {
        LambdaQueryWrapper<OrderProfitsharing> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderProfitsharing::getOrderId, orderId);
        OrderProfitsharing orderProfitsharing = orderProfitsharingMapper.selectOne(queryWrapper);

        OrderProfitsharingVo orderProfitsharingVo = new OrderProfitsharingVo();
        BeanUtils.copyProperties(orderProfitsharing, orderProfitsharingVo);

        return orderProfitsharingVo;
    }

    //司机发送账单给乘客->更新订单状态信息：待付款
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        //更新订单信息
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, orderId);
        queryWrapper.eq(OrderInfo::getDriverId, driverId);

        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.UNPAID.getStatus());

        int row = orderInfoMapper.update(orderInfo, queryWrapper);

        if (row == 1) {
            this.log(orderId, OrderStatus.UNPAID.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    //乘客获取订单的支付信息
    @Override
    public OrderPayVo getOrderPayVo(String orderNo, Long customerId) {
        OrderPayVo orderPayVo = orderInfoMapper.selectOrderPayVo(orderNo, customerId);
        if(orderPayVo!=null){
            String content = "从"+orderPayVo.getStartLocation() +"到"+orderPayVo.getEndLocation();
            orderPayVo.setContent(content);
        }

        return orderPayVo;
    }

    //更新订单状态
    @Override
    public Boolean updateOrderPayStatus(String orderNo) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getOrderNo, orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        if(orderInfo==null||orderInfo.getStatus()==OrderStatus.PAID.getStatus()){
            return true;
        }

        LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderInfo::getOrderNo, orderNo);
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.PAID.getStatus());

        int row = orderInfoMapper.update(orderInfo, wrapper);
        if(row==1){
            return true;
        }else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
    }


    @Override
    public OrderRewardVo getOrderRewardFee(String orderNo) {
        //1.查询orderInfo表
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getOrderNo, orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);

        //2.查询orderBill表
        LambdaQueryWrapper<OrderBill> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderBill::getOrderId, orderInfo.getId() );
        OrderBill orderBill = orderBillMapper.selectOne(wrapper);

        OrderRewardVo orderRewardVo = new OrderRewardVo();
        orderRewardVo.setOrderId(orderInfo.getId());
        orderRewardVo.setDriverId(orderInfo.getDriverId());
        orderRewardVo.setRewardFee(orderBill.getRewardFee());

        return orderRewardVo;
    }

    //取消订单
    @Override
    public void orderCancel(Long orderId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, orderId);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);

        //没人接单才会取消
        if(orderInfo.getStatus()==OrderStatus.WAITING_ACCEPT.getStatus()){
            orderInfo.setStatus(OrderStatus.CANCEL_ORDER.getStatus());
            int row = orderInfoMapper.updateById(orderInfo);
            if(row==1){
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK);
            }
        }
    }


    //更新订单信息，订单状态->已到达
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, updateOrderCartForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId());
        OrderInfo updateOrderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, updateOrderInfo);
        updateOrderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        //只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            //记录日志
            this.log(updateOrderCartForm.getOrderId(), OrderStatus.UPDATE_CART_INFO.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, orderId);
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        //更新的对象数据信息
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.DRIVER_ARRIVED.getStatus());
        updateOrderInfo.setArriveTime(new Date());
        //只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            //记录日志
            this.log(orderId, OrderStatus.DRIVER_ARRIVED.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        //司机发送完账单，司机端主要流程就走完（当前这些节点，司机端会调整到相应的页面处理逻辑）
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus()
        };
        queryWrapper.in(OrderInfo::getStatus, statusArray);
        queryWrapper.orderByDesc(OrderInfo::getId);
        queryWrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if (null != orderInfo) {
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        } else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    @Override
    public Long getOrderNumByTime(String startTime, String endTime) {
        //查询条件的构建
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(OrderInfo::getStartServiceTime, startTime);
        queryWrapper.lt(OrderInfo::getEndServiceTime, endTime);
        //查询
        Long count = orderInfoMapper.selectCount(queryWrapper);
        return count;
    }


    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getCustomerId, customerId);
        //乘客端支付完订单，乘客端主要流程就走完（当前这些节点，乘客端会调整到相应的页面处理逻辑）
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
                OrderStatus.UNPAID.getStatus()
        };
        queryWrapper.in(OrderInfo::getStatus, statusArray);
        queryWrapper.orderByDesc(OrderInfo::getId);
        queryWrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if (null != orderInfo) {
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        } else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        //抢单成功或取消订单，都会删除该key，redis判断，减少数据库压力
        if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId)) {
            //抢单失败
            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }

        // 初始化分布式锁，创建一个RLock实例
        RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);
        try {
            /**
             * TryLock是一种非阻塞式的分布式锁，实现原理：Redis的SETNX命令
             * 参数：
             *     waitTime：等待获取锁的时间
             *     leaseTime：加锁的时间
             */
            boolean flag = lock.tryLock(RedisConstant.ROB_NEW_ORDER_LOCK_WAIT_TIME, RedisConstant.ROB_NEW_ORDER_LOCK_LEASE_TIME, TimeUnit.SECONDS);
            //获取到锁
            if (flag) {
                //二次判断，防止重复抢单
                if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId)) {
                    //抢单失败
                    throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }

                //修改订单状态
                //update order_info set status = 2, driver_id = #{driverId} where id = #{id}
                //修改字段
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setId(orderId);
                orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
                orderInfo.setAcceptTime(new Date());
                orderInfo.setDriverId(driverId);
                int rows = orderInfoMapper.updateById(orderInfo);
                if (rows != 1) {
                    //抢单失败
                    throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }

                //记录日志
                this.log(orderId, orderInfo.getStatus());

                //删除redis订单标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderId);
            }
        } catch (InterruptedException e) {
            //抢单失败
            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return true;
        //不使用redission的抢单
//        System.out.println("抢单service实现中的driverId:"+driverId);
//        System.out.println("抢单service实现中的orderId:"+orderId);
//        //抢单成功或取消订单，都会删除该key，redis判断，减少数据库压力
//        if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK+orderId)) {
//            //抢单失败
//            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
//        }
//
//        //修改订单状态及司机id
//        //update order_info set status = 2, driver_id = #{driverId}, accept_time = now() where id = #{id}
//        //修改字段
//        OrderInfo orderInfo = new OrderInfo();
//        orderInfo.setId(orderId);
//        orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
//        orderInfo.setAcceptTime(new Date());
//        orderInfo.setDriverId(driverId);
//        int rows = orderInfoMapper.updateById(orderInfo);
//        if (rows != 1) {
//            //抢单失败
//            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
//        }
//        //记录日志
//        this.log(orderId, orderInfo.getStatus());
//
//        //删除redis订单标识
//        redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK);
//        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        System.out.println("startDriveForm:"+startDriveForm);

        //构建了查询的条件
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, startDriveForm.getOrderId());
        queryWrapper.eq(OrderInfo::getDriverId, startDriveForm.getDriverId());
        //更新订单状态
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());
        updateOrderInfo.setStartServiceTime(new Date());
        //只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        System.out.println("row:"+row);
        if (row == 1) {
            //记录日志
            this.log(startDriveForm.getOrderId(), OrderStatus.START_SERVICE.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        //把订单监控统计的数据表进行初始化【先提供一条对应订单的监控的数据（数据是为空的）】
        OrderMonitor orderMonitor = new OrderMonitor();
        orderMonitor.setOrderId(startDriveForm.getOrderId());
        //保存orderMonitor数据
        orderMonitorMapper.insert(orderMonitor);
        return true;
    }


    //根据订单id查询状态
    @Override
    public Integer getOrderStatus(Long orderId) {
        //查询数据、指定返回status信息
        OrderInfo orderInfo = orderInfoMapper.selectOne(
                new LambdaQueryWrapper<OrderInfo>()
                        .eq(OrderInfo::getId, orderId)
                        .select(OrderInfo::getStatus)
        );
        //判断数据不为空\空则抛出异常
        if (orderInfo == null) {
            return OrderStatus.NULL_ORDER.getStatus();
        }
        //返回状态
        return orderInfo.getStatus();
    }

    //保存订单信息
    @Override
    public Long saveOrderInfo(OrderInfoForm orderInfoForm) {
        //1、OrderInfoForm  -- > OrderInfo [订单编号  UUID]  -->新增数据
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoForm, orderInfo);
        //订单编号
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        orderInfo.setOrderNo(orderNo);
        orderInfo.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());
        orderInfoMapper.insert(orderInfo);

        //实现延迟队列，15分钟后自动取消
        this.sendDelayMessage(orderInfo.getId());

        //2、订单的日志记录--新增
        this.log(orderInfo.getId(), orderInfo.getStatus());
        //3、通过redis来存放当前的订单信息【等待15分钟】
        redisTemplate.opsForValue().set(RedisConstant.ORDER_ACCEPT_MARK + orderInfo.getId().toString(), "0", RedisConstant.ORDER_ACCEPT_MARK_EXPIRES_TIME, TimeUnit.MINUTES);
        return orderInfo.getId();
    }

    //redission实现延迟队列
    private void sendDelayMessage(Long id) {
        try {
            //1.创建队列
            RBlockingQueue<Object> delay_queue = redissonClient.getBlockingQueue("delay_queue");

            //2.放到延迟队列中
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(delay_queue);
            //3.发送信息到延迟队列里边
            //设置过期时间
            delayedQueue.offer(id.toString(), 15, TimeUnit.MINUTES);
        }catch (Exception e){
            throw new AnanException(ResultCodeEnum.DATA_ERROR);
        }
    }


    public void log(Long orderId, Integer status) {
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderId);
        orderStatusLog.setOrderStatus(status);
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
    }
}
